package edu.nyu.hps.assignment4;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;

public class Computation {

	People p[];
	Hospital h[];
	Ambulance a[];
	int anyOneAlive, numP, numH, instant, totalSaved, bestSaved, couldSave;
	public static int grid[][] = new int[100][100];

	List<String> routes = new ArrayList<String>();

	/**
	 * Constructor to initialise objects
	 * 
	 * @param dataForPeople
	 * @param dataForHospital
	 */
	public Computation(List<String> dataForPeople, List<String> dataForHospital) {

		this.numP = dataForPeople.size();
		this.numH = dataForHospital.size();
		instant = 0;
		anyOneAlive = dataForPeople.size();
		this.totalSaved = 0;
		this.bestSaved = 0;
		this.couldSave = 0;
		p = new People[dataForPeople.size()];
		h = new Hospital[dataForHospital.size()];

		for (int i = 0; i < dataForPeople.size(); i++) {
			String[] arr = dataForPeople.get(i).split(",");
			int x = Integer.parseInt(arr[0]);
			int y = Integer.parseInt(arr[1]);
			int rescueTime = Integer.parseInt(arr[2]);
			int index = i;
			People pt = new People(x, y, rescueTime, index);
			p[i] = pt;

		}

		for (int i = 0; i < dataForHospital.size(); i++) {
			String[] arr = dataForHospital.get(i).split(",");
			int x = Integer.parseInt(arr[0]);
			int y = Integer.parseInt(arr[1]);
			int maxAmbulance = Integer.parseInt(arr[2]);
			int index = i;
			Hospital ht = new Hospital(x, y, maxAmbulance, index);
			h[i] = ht;
		}

		List<Ambulance> ambulanceArray = new ArrayList<Ambulance>();
		for (int i = 0; i < h.length; i++) {
			for (int j = 0; j < h[i].maxAmbulance; j++) {
				Ambulance at = new Ambulance(h[i]);
				ambulanceArray.add(at);
			}
		}

		a = new Ambulance[ambulanceArray.size()];
		for (int i = 0; i < ambulanceArray.size(); i++) {
			a[i] = ambulanceArray.get(i);
			a[i].index= i;
		}

		// Calculate the nearest hospital for each person
		for (int i = 0; i < numP; i++) {
			int dist = 100;
			for (int j = 0; j < numH; j++) {
				int temp = distBetHnP(j, i);
				if (temp < dist) {
					dist = temp;
					p[i].h = h[j];
				}
			}
		}
	}

	/**
	 * Calculates distance between hospital i and person j
	 * 
	 * @param i
	 * @param j
	 * @return distance
	 */
	public int distBetHnP(int i, int j) {
		return (Math.abs(h[i].x - p[j].x) + Math.abs(h[i].y - p[j].y));
	}

	/**
	 * Calculates distance between person i and person j
	 * 
	 * @param i
	 * @param j
	 * @return
	 */
	public int distBetPnP(int i, int j) {
		return (Math.abs(p[i].x - p[j].x) + Math.abs(p[i].y - p[j].y));
	}

	/**
	 * Determines if the person i and j can be saved in the whole journey
	 * 
	 * @param i
	 * @param j
	 * @param journey
	 * @return true if the people can be saved
	 */
	public boolean canSave(int i, int j, int journey) {
		if (journey <= p[i].rescueTime && journey <= p[j].rescueTime) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Determines if a person i can be saved within the journey
	 * 
	 * @param i
	 * @param journey
	 * @return
	 */
	public boolean canSave(int i, int journey) {
		if (journey <= p[i].rescueTime) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Updates the density of people around the hospital
	 */
	public void updateDensityOfHospital() {
		for (int i = 0; i < h.length; i++) {
			h[i].density = 0;
		}
		for (int i = 0; i < p.length; i++) {
			if(p[i].x==p[i].h.x && p[i].y == p[i].h.y){p[i].isSaved=true;}
			if (!p[i].isSaved) {
				h[p[i].h.index].density++;
			}
		}

		// List<People> peopleArray = Arrays.asList(p);
		// Collections.sort(peopleArray);
		//
		// for (int i = 0; i < numP; i++) {
		// p[i] = peopleArray.get(i);
		// }
	}

	/**
	 * Updates rescue time for each patient, each time
	 */
	public void reduceRescueTime() {
		anyOneAlive = 0;
		for (int i = 0; i < numP; i++) {
			if (p[i].rescueTime > 0) {
				p[i].rescueTime -= 1;
				anyOneAlive++;
			}
		}
	}

	/**
	 * Reset data of successive runs
	 */
	public void reset() {
		instant = 0;
		anyOneAlive = numP;
		totalSaved = 0;
		couldSave = 0;
		routes.clear();

		// Resets for the hospital data
		for (int i = 0; i < numH; i++) {
			h[i].casualties = 0;
		}

		// Resets for the people data
		for (int i = 0; i < numP; i++) {
			if (p[i].isSaved) {
				h[p[i].h.index].casualties++;
				p[i].timesSurvived += 1;
				p[i].isSaved = false;
			}
			p[i].rescueTime = p[i].origRescueTime;
		}

		List<People> peopleArray = Arrays.asList(p);
		Collections.sort(peopleArray);

		
		for (int i = 0; i < numP; i++) {
			p[i] = peopleArray.get(i);
		}

		// Resets for the ambulance data
		for (int i = 0; i < a.length; i++) {
			a[i].time = 0;
			a[i].h = a[i].origH;
		}
		List<Ambulance> ambArray = Arrays.asList(a);
		Collections.sort(ambArray);
		for (int i = 0; i < ambArray.size(); i++) {
			a[i] = ambArray.get(i);
		}
		reducePh();
	}

	public void reducePh(){
		int i,j;
		for(i=0;i<100;i++){
			for(j=0;j<100;j++){
				grid[i][j] -=25;
			}
		}
	}
	/**
	 * The actual computation that saves victims
	 */
	public void startSaving() {
		reset();
		updateDensityOfHospital();
		while (anyOneAlive != 0) {
			for (int i = 0; i < a.length; i++) {
				couldSave = 0;
				if (a[i].time <= instant) {
					for (int j = 0; j < numP; j++) {
						if (!p[j].isSaved) {
							if(p[j].h==a[i].h){		
								int distance1 = distBetHnP(a[i].h.index, j)
										+ distBetHnP(p[j].h.index, j) + 2;
								if (canSave(j, distance1)) {
									couldSave = 1;
									for (int k = 0; k < numP; k++) {
										if (!p[k].isSaved && k != j
												&& !p[j].isSaved) {
											int distance2 = distBetHnP(
													a[i].h.index, j)
													+ distBetPnP(j, k)
													+ distBetHnP(p[k].h.index, k)
													+ 3;
											if (canSave(j, k, distance2)) {
												couldSave = 2;
												if(p[j] == null) {
													System.out.println("p[k] null"+k);
												}
												a[i].phBasedChoice(p[j],p[k],distance2);										}
										}
									}
									if (couldSave==1 && !p[j].isSaved) {
										a[i].phBasedChoice(p[j], distance1);								
									}
									else if (couldSave ==2 ) break;
								}
							}
							else continue;
						}
					}
					if((couldSave == 1 && a[i].p1!= null) || (couldSave == 2 && a[i].p1 !=null&& a[i].p2 !=null)) {
						routes.add(a[i].getPath(couldSave));
					}
					a[i].p1 = null;
					a[i].p2 = null;
					totalSaved+=couldSave;
					updateDensityOfHospital();
				}
			}
			instant++;
			reduceRescueTime();
		}
	}
}
